package com.ccrfid.rmc6.service.personnel;

import com.ccrfid.rmc6.appconfig.exception.pojo.AppException;
import com.ccrfid.rmc6.appconfig.exception.pojo.CustomErrors;
import com.ccrfid.rmc6.entity.device.CardEntity;
import com.ccrfid.rmc6.entity.personnel.PersonnelEntity;
import com.ccrfid.rmc6.entity.personnel.PersonnelPhotoEntity;
import com.ccrfid.rmc6.entity.personnel.PersonnelPrisonerEntity;
import com.ccrfid.rmc6.entity.personnel.PersonnelPrisonerView;
import com.ccrfid.rmc6.entity.sys.OrgEntity;
import com.ccrfid.rmc6.lbservice3.mq.MsgDispatcher;
import com.ccrfid.rmc6.pojo.Constants;
import com.ccrfid.rmc6.pojo.dto.sync.PrisonerCardDto;
import com.ccrfid.rmc6.pojo.dto.sync.SyncExternalDto;
import com.ccrfid.rmc6.pojo.dto.sync.SyncPoliceDto;
import com.ccrfid.rmc6.pojo.dto.sync.SyncPrisonerDto;
import com.ccrfid.rmc6.repository.device.CardRepository;
import com.ccrfid.rmc6.repository.personnel.PersonnelPhotoRepository;
import com.ccrfid.rmc6.repository.personnel.PersonnelPrisonerRepository;
import com.ccrfid.rmc6.repository.personnel.PersonnelPrisonerViewRepository;
import com.ccrfid.rmc6.repository.personnel.PersonnelRepository;
import com.ccrfid.rmc6.repository.sys.OrgRepository;
import com.ccrfid.rmc6.service.device.CardService;
import me.xuender.unidecode.Unidecode;
import org.hibernate.query.NativeQuery;
import org.hibernate.transform.Transformers;
import org.hibernate.type.LongType;
import org.hibernate.type.StringType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
import javax.ws.rs.core.Response;
import java.sql.Timestamp;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Service
@Transactional
public class SyncPrisonerServiceImpl implements SyncPrisonerService {
    private static final Logger logger = LoggerFactory.getLogger(SyncPrisonerServiceImpl.class);
    @Autowired
    private EntityManager entityManager;
    @Autowired
    private PersonnelRepository personnelRepository;
    @Autowired
    private PersonnelPrisonerRepository personnelPrisonerRepository;
    @Autowired
    private PersonnelPrisonerViewRepository personnelPrisonerViewRepository;
    @Autowired
    private OrgRepository orgRepository;
    @Autowired
    private MsgDispatcher msgDispatcher;
    @Autowired
    private CardRepository cardRepository;
    @Autowired
    private CardService cardService;
    @Autowired
    private PersonnelPhotoRepository personnelPhotoRepository;

    @Autowired
    private SyncPrisonerService syncPrisonerService;    //注入自己，调用自己的方法，否则AOP不会捕获到该类自己内部调用的方法

    @Value("${rmc6.image.max_allowed_packet}")
    private int maxAllowedPacket;
    @Value("${prison.self.cardbind}")
    private String prisonSelfBind;
    @Value("${prison.thirdparty.cardbind}")
    private String prison3rdpartyBind;

    private Set<String> prisonSelfBindSet = new HashSet<>();
    private Set<String> prison3rdpartyBindSet = new HashSet<>();

    @PostConstruct
    public void init() {
        for (String prisonId : prisonSelfBind.split(",")) {
            prisonSelfBindSet.add(StringUtils.trimWhitespace(prisonId));
        }
        for (String prisonId : prison3rdpartyBind.split(",")) {
            prison3rdpartyBindSet.add(StringUtils.trimWhitespace(prisonId));
        }
    }

    @Override
    public Timestamp getUpdateTime() {
        Timestamp timestamp = personnelPrisonerRepository.getMaxUpdatetime();
        if (timestamp == null) {
            return new Timestamp(0);
        } else {
            return timestamp;
        }
    }

    @Override
    public SyncPrisonerDto getPrisonerInfo(String personnelSn) {
        if (personnelPrisonerViewRepository.existsByPersonnelSn(personnelSn)) {
            PersonnelPrisonerView prisonerView = personnelPrisonerViewRepository.getByPersonnelSn(personnelSn);
            if (prisonerView != null) {
                SyncPrisonerDto prisonerDto = new SyncPrisonerDto(prisonerView);
                return prisonerDto;
            }
        }
        return null;
    }

    @Override
    public void updatePrisonerPhoto(String personnelSn, byte[] image) throws AppException {
        if (!personnelRepository.existsByPersonnelSn(personnelSn)) {
            throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                    CustomErrors.person_not_found.getCode(), CustomErrors.person_not_found.getReason(), "");
        }
        if (image != null && image.length > maxAllowedPacket) {
            throw new AppException(Response.Status.REQUEST_ENTITY_TOO_LARGE.getStatusCode(),
                    CustomErrors.image_too_large.getCode(), CustomErrors.image_too_large.getReason(), "");
        }
        PersonnelEntity personnelEntity = personnelRepository.getByPersonnelSn(personnelSn);
        PersonnelPhotoEntity photoEntity = new PersonnelPhotoEntity();
        photoEntity.setPersonnelId(personnelEntity.getId());
        photoEntity.setImage(image);
        personnelPhotoRepository.save(photoEntity);
    }

    @Override
    public byte[] getPrisonerPhoto(String personnelSn) {
        PersonnelEntity personnelEntity = personnelRepository.getByPersonnelSn(personnelSn);
        if (personnelEntity != null) {
            PersonnelPhotoEntity photoEntity = personnelPhotoRepository.getByPersonnelId(personnelEntity.getId());
            if (photoEntity != null) {
                return photoEntity.getImage();
            }
        }
        return null;
    }

    @Override
    public Boolean existPhoto(String personnelSn) throws AppException {
        if (!personnelRepository.existsByPersonnelSn(personnelSn)) {
            throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                    CustomErrors.person_not_found.getCode(), CustomErrors.person_not_found.getReason(), "");
        }
        PersonnelEntity personnelEntity = personnelRepository.getByPersonnelSn(personnelSn);
        return personnelPhotoRepository.existsByPersonnelId(personnelEntity.getId());
    }

    @Override
    public void updatePrisonerInfo(String prisonId, SyncPrisonerDto prisonerDto) throws AppException {
        if (prisonerDto.getPersonnelSn() == null) {
            throw new AppException(Response.Status.FORBIDDEN.getStatusCode(),
                    CustomErrors.person_sn_is_null.getCode(), CustomErrors.person_sn_is_null.getReason(), "");
        }
        if (prisonerDto.getPersonnelName() == null) {
            throw new AppException(Response.Status.FORBIDDEN.getStatusCode(),
                    CustomErrors.person_name_is_null.getCode(), CustomErrors.person_name_is_null.getReason(), "");
        }
        if (prisonerDto.getNameAcronym() == null) {
            prisonerDto.setNameAcronym(Unidecode.initials(prisonerDto.getPersonnelName()));
        }
        //unifoNo 番号可能为空
//        if (prisonerDto.getUnifoNo() == null) {
//            throw new AppException(Response.Status.FORBIDDEN.getStatusCode(),
//                    CustomErrors.unifo_is_null.getCode(), CustomErrors.unifo_is_null.getReason(), "");
//        }
        if (prisonerDto.getDormCode() != null) {
            if (!orgRepository.existsByOrgSn(prisonerDto.getDormCode())) {
                throw new AppException(Response.Status.FORBIDDEN.getStatusCode(),
                        CustomErrors.org_not_found.getCode(), CustomErrors.org_not_found.getReason(),
                        "dormCode:" + prisonerDto.getDormCode());
            }
        }
        if (prisonerDto.getCardNumber() != null) {
            if (!cardRepository.existsByCardNumber(prisonerDto.getCardNumber())) {
                //自动创建标签
                CardEntity cardEntity = new CardEntity();
                cardEntity.setCardNumber(prisonerDto.getCardNumber());
                cardEntity.setCardType(Constants.CARD_TYPE.BAND.id);
                cardEntity.setEnabled(Constants.ENABLE_STATUS.ENABLE.id);
                cardService.createCard(cardEntity);
            }
        }
        if (prisonSelfBindSet.contains(prisonId)) {
            //在自己平台绑定标签
            updatePrisonerInfoSelfBind(prisonerDto);
        } else if (prison3rdpartyBind.contains(prisonId)) {
            //在第三方平台绑定标签
            Long cardNumber = prisonerDto.getCardNumber();
            if (cardNumber != null) {
                PersonnelEntity personnelEntity = personnelRepository.getByCardNumber(cardNumber);
                if (personnelEntity != null && (!prisonerDto.getPersonnelSn().equals(personnelEntity.getPersonnelSn()))) {
                    throw new AppException(Response.Status.FORBIDDEN.getStatusCode(),
                            CustomErrors.card_number_conflict.getCode(), CustomErrors.card_number_conflict.getReason(),
                            "cardNumber:" + cardNumber + ", " + Long.toHexString(cardNumber));
                }
            }
            updatePrisonerInfo3rdBind(prisonerDto);
        } else {
            throw new AppException(Response.Status.FORBIDDEN.getStatusCode(),
                    CustomErrors.prisonId_not_found.getCode(), CustomErrors.prisonId_not_found.getReason(),
                    "prisonId:" + prisonId);
        }
    }

    @Override
    public void updatePrisonerInfoSelfBind(SyncPrisonerDto prisonerDto) throws AppException {
        //unifoNo 番号不能为空
        if (prisonerDto.getUnifoNo() == null) {
            throw new AppException(Response.Status.FORBIDDEN.getStatusCode(),
                    CustomErrors.unifo_is_null.getCode(), CustomErrors.unifo_is_null.getReason(), "");
        }
        String personnelSn = prisonerDto.getPersonnelSn();
        String unifoNo = prisonerDto.getUnifoNo();
        if (personnelRepository.existsByPersonnelSn(personnelSn)) {
            //更新
            syncPrisonerService.updatePrisonerInfoSelfBindUpdateByPersonnelSn(prisonerDto);
        } else {
            if (personnelPrisonerViewRepository.existsByUnifoNoAndPersonnelSnIsNull(unifoNo)) {
                //更新
                syncPrisonerService.updatePrisonerInfoSelfBindUpdateByUnifoNo(prisonerDto);
            } else {
                //新建
                syncPrisonerService.updatePrisonerInfoSelfBindCreate(prisonerDto);
            }
        }
    }

    @Override
    public PersonnelEntity updatePrisonerInfoSelfBindUpdateByPersonnelSn(SyncPrisonerDto prisonerDto) {
        PersonnelEntity personnelEntity = personnelRepository.getByPersonnelSn(prisonerDto.getPersonnelSn());
        PersonnelPrisonerEntity prisonerEntity = personnelPrisonerRepository.getByPersonnelId(personnelEntity.getId());
        if (prisonerEntity == null) {
            prisonerEntity = new PersonnelPrisonerEntity();
            prisonerEntity.setPersonnelId(personnelEntity.getId());
        }
        updatePrisonerEntities(personnelEntity, prisonerEntity, prisonerDto);

        return personnelEntity;
    }

    @Override
    public PersonnelEntity updatePrisonerInfoSelfBindUpdateByUnifoNo(SyncPrisonerDto prisonerDto) {
        PersonnelPrisonerView prisonerView = personnelPrisonerViewRepository.getByUnifoNoAndPersonnelSnIsNull(prisonerDto.getUnifoNo());
        PersonnelEntity personnelEntity = personnelRepository.getById(prisonerView.getId());
        PersonnelPrisonerEntity prisonerEntity = personnelPrisonerRepository.getByPersonnelId(personnelEntity.getId());
        if (prisonerEntity == null) {
            prisonerEntity = new PersonnelPrisonerEntity();
            prisonerEntity.setPersonnelId(personnelEntity.getId());
        }
        personnelEntity.setPersonnelSn(prisonerDto.getPersonnelSn());
        updatePrisonerEntities(personnelEntity, prisonerEntity, prisonerDto);

        return personnelEntity;
    }

    @Override
    public PersonnelEntity updatePrisonerInfoSelfBindCreate(SyncPrisonerDto prisonerDto) {
        PersonnelEntity personnelEntity = new PersonnelEntity();
        copyValues(personnelEntity, prisonerDto);
        if (prisonerDto.getOutTime() == null) {
            personnelEntity.setEnabled(1);
        } else {
            personnelEntity.setEnabled(0);
        }
        personnelEntity.setPersonnelSn(prisonerDto.getPersonnelSn());
        //1.机构设置
        if (prisonerDto.getDormCode() != null) {
            OrgEntity orgEntity = orgRepository.getByOrgSn(prisonerDto.getDormCode());
            if (orgEntity != null) {
                personnelEntity.setOrgId(orgEntity.getId());
            } else {
                personnelEntity.setOrgId(null);
                logger.error("cannot find dormCode: {}", prisonerDto.getDormCode());
            }
        }
        personnelEntity = personnelRepository.save(personnelEntity);

        PersonnelPrisonerEntity prisonerEntity = new PersonnelPrisonerEntity();
        copyValues(prisonerEntity, prisonerDto);
        prisonerEntity.setOutTime(prisonerDto.getOutTime());
        prisonerEntity.setPersonnelId(personnelEntity.getId());
        personnelPrisonerRepository.save(prisonerEntity);

        return personnelEntity;
    }

    private void updatePrisonerEntities(PersonnelEntity personnelEntity, PersonnelPrisonerEntity prisonerEntity, SyncPrisonerDto prisonerDto) {
        copyValues(personnelEntity, prisonerDto);
        copyValues(prisonerEntity, prisonerDto);
        //1.机构调换
        if (prisonerDto.getDormCode() != null) {
            OrgEntity orgEntity = orgRepository.getByOrgSn(prisonerDto.getDormCode());
            if (orgEntity != null) {
                personnelEntity.setOrgId(orgEntity.getId());
            } else {
                personnelEntity.setOrgId(null);
                logger.error("cannot find dormCode: {}", prisonerDto.getDormCode());
            }
        } else {
            personnelEntity.setOrgId(null);
        }
        //2.出所判断
        Long cardNumber = null;
        if (prisonerEntity.getOutTime() == null && prisonerDto.getOutTime() != null) {
            personnelEntity.setEnabled(0);
            if (personnelEntity.getCardNumber() != null) {
                cardNumber = personnelEntity.getCardNumber();
                personnelEntity.setCardNumber(null);
            }
        }
        if (prisonerEntity.getOutTime() != null && prisonerDto.getOutTime() == null) {
            personnelEntity.setEnabled(Constants.ENABLE_STATUS.ENABLE.id);
        }
        prisonerEntity.setOutTime(prisonerDto.getOutTime());
        //save
        personnelRepository.save(personnelEntity);
        personnelPrisonerRepository.save(prisonerEntity);
        if (cardNumber != null) {
            msgDispatcher.unBindPersonnelCard(personnelEntity.getId(), cardNumber);
        }
    }

    @Override
    public void updatePrisonerInfo3rdBind(SyncPrisonerDto prisonerDto) {
        if (personnelRepository.existsByPersonnelSn(prisonerDto.getPersonnelSn())) {
            //更新
            syncPrisonerService.updatePrisonerInfo3rdBindUpdate(prisonerDto);
        } else {
            //新建
            syncPrisonerService.updatePrisonerInfo3rdBindCreate(prisonerDto);
        }
    }

    @Override
    public PersonnelEntity updatePrisonerInfo3rdBindCreate(SyncPrisonerDto prisonerDto) {
        PersonnelEntity personnelEntity = new PersonnelEntity();
        copyValues(personnelEntity, prisonerDto);
        if (prisonerDto.getOutTime() == null) {
            //未出所
            personnelEntity.setEnabled(1);
            personnelEntity.setCardNumber(prisonerDto.getCardNumber());
        } else {
            //已出所
            personnelEntity.setEnabled(0);
            personnelEntity.setCardNumber(null);
        }
        personnelEntity.setPersonnelSn(prisonerDto.getPersonnelSn());
        //1.机构设置
        if (prisonerDto.getDormCode() != null) {
            OrgEntity orgEntity = orgRepository.getByOrgSn(prisonerDto.getDormCode());
            if (orgEntity != null) {
                personnelEntity.setOrgId(orgEntity.getId());
            } else {
                personnelEntity.setOrgId(null);
                logger.error("cannot find dormCode: {}", prisonerDto.getDormCode());
            }
        }
        personnelEntity = personnelRepository.save(personnelEntity);
        //2.绑定手环
        if (personnelEntity.getCardNumber() != null) {
            msgDispatcher.bindPersonnelCard(personnelEntity.getId(), personnelEntity.getCardNumber());
        }
        PersonnelPrisonerEntity prisonerEntity = new PersonnelPrisonerEntity();
        copyValues(prisonerEntity, prisonerDto);
        prisonerEntity.setOutTime(prisonerDto.getOutTime());
        prisonerEntity.setPersonnelId(personnelEntity.getId());
        personnelPrisonerRepository.save(prisonerEntity);

        return personnelEntity;
    }

    @Override
    public PersonnelEntity updatePrisonerInfo3rdBindUpdate(SyncPrisonerDto prisonerDto) {
        PersonnelEntity personnelEntity = personnelRepository.getByPersonnelSn(prisonerDto.getPersonnelSn());
        PersonnelPrisonerEntity prisonerEntity = personnelPrisonerRepository.getByPersonnelId(personnelEntity.getId());
        if (prisonerEntity == null) {
            prisonerEntity = new PersonnelPrisonerEntity();
            prisonerEntity.setPersonnelId(personnelEntity.getId());
        }
        copyValues(personnelEntity, prisonerDto);
        copyValues(prisonerEntity, prisonerDto);
        //1.机构调整
        if (prisonerDto.getDormCode() != null) {
            OrgEntity orgEntity = orgRepository.getByOrgSn(prisonerDto.getDormCode());
            if (orgEntity != null) {
                personnelEntity.setOrgId(orgEntity.getId());
            } else {
                personnelEntity.setOrgId(null);
                logger.error("cannot find dormCode: {}", prisonerDto.getDormCode());
            }
        } else {
            personnelEntity.setOrgId(null);
        }
        //2.出所判断
        Long cardNumber = personnelEntity.getCardNumber();
        if (prisonerEntity.getOutTime() == null && prisonerDto.getOutTime() != null) {
            personnelEntity.setEnabled(0);
            if (cardNumber != null) {
                personnelEntity.setCardNumber(null);
                msgDispatcher.unBindPersonnelCard(personnelEntity.getId(), cardNumber);
            }
        }
        if (prisonerEntity.getOutTime() != null && prisonerDto.getOutTime() == null) {
            personnelEntity.setEnabled(Constants.ENABLE_STATUS.ENABLE.id);
        }
        prisonerEntity.setOutTime(prisonerDto.getOutTime());
        //2.未出所人员，手环调整
        if (prisonerEntity.getOutTime() == null) {
            Long dtoCardNumber = prisonerDto.getCardNumber();
            if (cardNumber == null) {
                if (dtoCardNumber != null) {
                    //佩戴手环
                    personnelEntity.setCardNumber(dtoCardNumber);
                    msgDispatcher.bindPersonnelCard(personnelEntity.getId(), dtoCardNumber);
                }
            } else {
                if (dtoCardNumber == null) {
                    //解绑手环
                    personnelEntity.setCardNumber(null);
                    msgDispatcher.unBindPersonnelCard(personnelEntity.getId(), cardNumber);
                } else {
                    if (!cardNumber.equals(dtoCardNumber)) {
                        //更换手环
                        personnelEntity.setCardNumber(dtoCardNumber);
                        msgDispatcher.unBindPersonnelCard(personnelEntity.getId(), cardNumber);
                        msgDispatcher.bindPersonnelCard(personnelEntity.getId(), dtoCardNumber);
                    }
                }
            }
        }
        //save
        personnelRepository.save(personnelEntity);
        personnelPrisonerRepository.save(prisonerEntity);

        return personnelEntity;
    }

    private void copyValues(PersonnelEntity personnelEntity, SyncPrisonerDto prisonerDto) {
        personnelEntity.setPersonnelName(prisonerDto.getPersonnelName());
        personnelEntity.setNameAcronym(prisonerDto.getNameAcronym());
        personnelEntity.setIdNumber(prisonerDto.getIdNumber());
        personnelEntity.setPersonnelType(101);
        personnelEntity.setGender(prisonerDto.getGender());
        personnelEntity.setBirthday(prisonerDto.getBirthday());
        //ignored: cardNumber, personnelSn, orgId, enabled
    }

    private void copyValues(PersonnelPrisonerEntity prisonerEntity, SyncPrisonerDto prisonerDto) {
        prisonerEntity.setAnotherName(prisonerDto.getAnotherName());
        prisonerEntity.setDormCode(prisonerDto.getDormCode());
        prisonerEntity.setEthnicGroupValue(prisonerDto.getEthnicGroupValue());
        prisonerEntity.setPoliticalStatusValue(prisonerDto.getPoliticalStatusValue());
        prisonerEntity.setNationalityValue(prisonerDto.getNationalityValue());
        prisonerEntity.setHouseAddrValue(prisonerDto.getHouseAddrValue());
        prisonerEntity.setHouseDetailAddr(prisonerDto.getHouseDetailAddr());
        prisonerEntity.setIdentityValue(prisonerDto.getIdentityValue());
        prisonerEntity.setWorkAddr(prisonerDto.getWorkAddr());
        prisonerEntity.setPosition(prisonerDto.getPosition());
        prisonerEntity.setSpecialtyValue(prisonerDto.getSpecialtyValue());
        prisonerEntity.setStageValue(prisonerDto.getStageValue());
        prisonerEntity.setResultValue(prisonerDto.getResultValue());
        prisonerEntity.setCaseTypeValue(prisonerDto.getCaseTypeValue());
        prisonerEntity.setBrief(prisonerDto.getBrief());
        prisonerEntity.setComeReasonValue(prisonerDto.getComeReasonValue());
        prisonerEntity.setJailTimeValue(prisonerDto.getJailTimeValue());
        prisonerEntity.setComeTime(prisonerDto.getComeTime());
        prisonerEntity.setUnifoNo(prisonerDto.getUnifoNo());
        prisonerEntity.setArrestDate(prisonerDto.getArrestDate());
        prisonerEntity.setImprisonLimit(prisonerDto.getImprisonLimit());
        prisonerEntity.setHandlingUnit(prisonerDto.getHandlingUnit());
        prisonerEntity.setManageTypeValue(prisonerDto.getManageTypeValue());
        prisonerEntity.setIsMajorCriminalOffender(prisonerDto.getIsMajorCriminalOffender());
        prisonerEntity.setIsFocusedPrisoner(prisonerDto.getIsFocusedPrisoner());
        prisonerEntity.setIsDeathPrisoner(prisonerDto.getIsDeathPrisoner());
        prisonerEntity.setIsInfectedPrisoner(prisonerDto.getIsInfectedPrisoner());
        prisonerEntity.setStakeType(prisonerDto.getStakeType());
        prisonerEntity.setHistoryCrime(prisonerDto.getHistoryCrime());
        prisonerEntity.setDealWith(prisonerDto.getDealWith());
        prisonerEntity.setUpdateTime(prisonerDto.getUpdateTime());
        prisonerEntity.setInvolvedCrime(prisonerDto.getInvolvedCrime());
        //ignored: outTime
    }

    @Override
    public List<PrisonerCardDto> getAllPrisonersWithCard() {
        String sql = "select p.id, p.personnel_name as personnelName, p.personnel_sn as personnelSn, p.unifo_no as unifoNo, " +
                " p.id_number as idNumber, p.card_number as cardNumber, d.uid as cardUid, d.sn as cardSn " +
                " from v_personnel_prisoner p " +
                " left join d_card d on p.card_number = d.card_number " +
                " where p.card_number is not null and p.is_enabled = 1";
        List<PrisonerCardDto> list = entityManager.createNativeQuery(sql)
                .unwrap(NativeQuery.class)
                .addScalar("id", LongType.INSTANCE)
                .addScalar("personnelName", StringType.INSTANCE)
                .addScalar("personnelSn", StringType.INSTANCE)
                .addScalar("unifoNo", StringType.INSTANCE)
                .addScalar("idNumber", StringType.INSTANCE)
                .addScalar("cardNumber", LongType.INSTANCE)
                .addScalar("cardUid", LongType.INSTANCE)
                .addScalar("cardSn", StringType.INSTANCE)
                .setResultTransformer(Transformers.aliasToBean(PrisonerCardDto.class))
                .list();
        return list;
    }

    @Override
    public SyncPoliceDto getPoliceInfo(String personnelSn) throws AppException {
        PersonnelEntity personnelEntity = personnelRepository.getByPersonnelSn(personnelSn);
        if (personnelEntity != null) {
            SyncPoliceDto policeDto = new SyncPoliceDto();
            policeDto.setCardNumber(personnelEntity.getCardNumber());
            policeDto.setPersonnelName(personnelEntity.getPersonnelName());
            policeDto.setNameAcronym(personnelEntity.getNameAcronym());
            policeDto.setPersonnelSn(personnelEntity.getPersonnelSn());
            policeDto.setIdNumber(personnelEntity.getIdNumber());
            if (personnelEntity.getOrgId() != null) {
                OrgEntity orgEntity = orgRepository.getById(personnelEntity.getOrgId());
                policeDto.setOrgCode(orgEntity != null ? orgEntity.getOrgSn() : null);
            }
            policeDto.setGender(personnelEntity.getGender());
            policeDto.setBirthday(personnelEntity.getBirthday());
            policeDto.setPhoneNumber(personnelEntity.getPhoneNumber());
            policeDto.setPdaNumber(personnelEntity.getShortNumber());
            policeDto.setTitle(personnelEntity.getTitle());
            policeDto.setCreateTime(personnelEntity.getCreateTime());
            policeDto.setUpdateTime(personnelEntity.getUpdateTime());
            return policeDto;
        } else {
            throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                    CustomErrors.person_not_found.getCode(), CustomErrors.person_not_found.getReason(), "");
        }
    }

    @Override
    public Boolean updatePoliceInfo(String prisonId, SyncPoliceDto policeDto) throws AppException {
        if (policeDto.getPersonnelSn() == null) {
            throw new AppException(Response.Status.FORBIDDEN.getStatusCode(),
                    CustomErrors.person_sn_is_null.getCode(), CustomErrors.person_sn_is_null.getReason(), "");
        }
        if (policeDto.getPersonnelName() == null) {
            throw new AppException(Response.Status.FORBIDDEN.getStatusCode(),
                    CustomErrors.person_name_is_null.getCode(), CustomErrors.person_name_is_null.getReason(), "");
        }
        if (policeDto.getNameAcronym() == null) {
            policeDto.setNameAcronym(Unidecode.initials(policeDto.getPersonnelName()));
        }
        if (policeDto.getCardNumber() != null) {
            if (!cardRepository.existsByCardNumber(policeDto.getCardNumber())) {
                //自动创建标签
                CardEntity cardEntity = new CardEntity();
                cardEntity.setCardNumber(policeDto.getCardNumber());
                cardEntity.setCardType(Constants.CARD_TYPE.CARD.id);
                cardEntity.setEnabled(Constants.ENABLE_STATUS.ENABLE.id);
                cardService.createCard(cardEntity);
            }
        }

        if (prisonSelfBindSet.contains(prisonId)) {
            //在自己平台绑定标签
            if (personnelRepository.existsByPersonnelSn(policeDto.getPersonnelSn())) {
                syncPrisonerService.updatePoliceInfoSelfBindUpdate(policeDto);
            } else {
                syncPrisonerService.updatePoliceInfoSelfBindCreate(policeDto);
            }
        } else if (prison3rdpartyBind.contains(prisonId)) {
            //在第三方平台绑定标签
            Long cardNumber = policeDto.getCardNumber();
            if (cardNumber != null) {
                PersonnelEntity personnelEntity = personnelRepository.getByCardNumber(cardNumber);
                if (personnelEntity != null && (!policeDto.getPersonnelSn().equals(personnelEntity.getPersonnelSn()))) {
                    throw new AppException(Response.Status.FORBIDDEN.getStatusCode(),
                            CustomErrors.card_number_conflict.getCode(), CustomErrors.card_number_conflict.getReason(),
                            "cardNumber:" + cardNumber + ", " + Long.toHexString(cardNumber));
                }
            }
            if (personnelRepository.existsByPersonnelSn(policeDto.getPersonnelSn())) {
                syncPrisonerService.updatePoliceInfo3rdBindUpdate(policeDto);
            } else {
                syncPrisonerService.updatePoliceInfo3rdBindCreate(policeDto);
            }
        } else {
            throw new AppException(Response.Status.FORBIDDEN.getStatusCode(),
                    CustomErrors.prisonId_not_found.getCode(), CustomErrors.prisonId_not_found.getReason(),
                    "prisonId:" + prisonId);
        }
        return true;
    }

    private PersonnelEntity updatePoliceInfoSelfBind(PersonnelEntity personnelEntity, SyncPoliceDto policeDto) {
        personnelEntity.setPersonnelName(policeDto.getPersonnelName());
        personnelEntity.setNameAcronym(policeDto.getNameAcronym());
        personnelEntity.setIdNumber(policeDto.getIdNumber());
        if (personnelEntity.getPersonnelType() == null) {
            personnelEntity.setPersonnelType(Constants.PERSONNEL_TYPE.POLICE.id);
        }
        //1.机构调换
        if (policeDto.getOrgCode() != null) {
            OrgEntity orgEntity = orgRepository.getByOrgSn(policeDto.getOrgCode());
            if (orgEntity != null) {
                personnelEntity.setOrgId(orgEntity.getId());
            } else {
                personnelEntity.setOrgId(null);
                logger.error("cannot find orgCode: {}, orgName: {}", policeDto.getOrgCode(), policeDto.getOrgName());
            }
        } else {
            personnelEntity.setOrgId(null);
        }
        if (policeDto.getDeleted() != null && policeDto.getDeleted().equals(1)) {
            personnelEntity.setEnabled(Constants.ENABLE_STATUS.DISABLE.id);
        } else {
            personnelEntity.setEnabled(Constants.ENABLE_STATUS.ENABLE.id);
        }
        personnelEntity.setGender(policeDto.getGender());
        personnelEntity.setBirthday(policeDto.getBirthday());
        personnelEntity.setPhoneNumber(policeDto.getPhoneNumber());
        personnelEntity.setShortNumber(policeDto.getPdaNumber());
        personnelEntity.setTitle(policeDto.getTitle());
//        personnelEntity.setCreateTime(policeDto.getCreateTime());
        personnelEntity.setUpdateTime(policeDto.getUpdateTime());
        return personnelRepository.save(personnelEntity);
    }

    public PersonnelEntity updatePoliceInfoSelfBindCreate(SyncPoliceDto policeDto) {
        PersonnelEntity personnelEntity = new PersonnelEntity();
        personnelEntity.setPersonnelSn(policeDto.getPersonnelSn());

        return updatePoliceInfoSelfBind(personnelEntity, policeDto);
    }

    public PersonnelEntity updatePoliceInfoSelfBindUpdate(SyncPoliceDto policeDto) {
        PersonnelEntity personnelEntity = personnelRepository.getByPersonnelSn(policeDto.getPersonnelSn());

        return updatePoliceInfoSelfBind(personnelEntity, policeDto);
    }

    public PersonnelEntity updatePoliceInfo3rdBindCreate(SyncPoliceDto policeDto) {
        PersonnelEntity personnelEntity = new PersonnelEntity();
        personnelEntity.setPersonnelSn(policeDto.getPersonnelSn());
        if (policeDto.getDeleted() != null && policeDto.getDeleted().equals(1)) {
            personnelEntity.setEnabled(Constants.ENABLE_STATUS.DISABLE.id);
            personnelEntity.setCardNumber(null);
        } else {
            personnelEntity.setEnabled(Constants.ENABLE_STATUS.ENABLE.id);
            personnelEntity.setCardNumber(policeDto.getCardNumber());
        }
        updatePoliceInfo3rdBind(personnelEntity, policeDto);
        //绑定手环
        if (personnelEntity.getCardNumber() != null) {
            msgDispatcher.bindPersonnelCard(personnelEntity.getId(), personnelEntity.getCardNumber());
        }

        return personnelEntity;
    }

    public PersonnelEntity updatePoliceInfo3rdBindUpdate(SyncPoliceDto policeDto) {
        PersonnelEntity personnelEntity = personnelRepository.getByPersonnelSn(policeDto.getPersonnelSn());
        if (policeDto.getDeleted() != null && policeDto.getDeleted().equals(1)) {
            //1.停用人员
            if (personnelEntity.getEnabled().equals(Constants.ENABLE_STATUS.ENABLE.id)) {
                //停用人员，解绑手环
                Long cardNumber = personnelEntity.getCardNumber();
                personnelEntity.setEnabled(Constants.ENABLE_STATUS.DISABLE.id);
                if (cardNumber != null) {
                    personnelEntity.setCardNumber(null);
                    msgDispatcher.unBindPersonnelCard(personnelEntity.getId(), cardNumber);
                }
            }
            //更新数据
            return updatePoliceInfo3rdBind(personnelEntity, policeDto);
        } else {
            //2.不停用人员
            if (personnelEntity.getEnabled().equals(Constants.ENABLE_STATUS.ENABLE.id)) {
                //调整手环编号
                Long cardNumber = personnelEntity.getCardNumber();
                Long newCardNumber = policeDto.getCardNumber();
                if (cardNumber != null) {
                    if (newCardNumber != null) {
                        if (!cardNumber.equals(newCardNumber)) {
                            //更换手环
                            personnelEntity.setCardNumber(newCardNumber);
                            msgDispatcher.unBindPersonnelCard(personnelEntity.getId(), cardNumber);
                            msgDispatcher.bindPersonnelCard(personnelEntity.getId(), newCardNumber);
                        }
                    } else {
                        //解绑手环
                        personnelEntity.setCardNumber(null);
                        msgDispatcher.unBindPersonnelCard(personnelEntity.getId(), cardNumber);
                    }
                } else {
                    if (newCardNumber != null) {
                        //绑定手环
                        personnelEntity.setCardNumber(newCardNumber);
                        msgDispatcher.bindPersonnelCard(personnelEntity.getId(), newCardNumber);
                    }
                }
            } else {
                //重新启用人员
                personnelEntity.setEnabled(Constants.ENABLE_STATUS.ENABLE.id);
                Long newCardNumber = policeDto.getCardNumber();
                if (newCardNumber != null) {
                    personnelEntity.setCardNumber(newCardNumber);
                    msgDispatcher.bindPersonnelCard(personnelEntity.getId(), newCardNumber);
                }
            }
            //更新数据
            return updatePoliceInfo3rdBind(personnelEntity, policeDto);
        }
    }

    private PersonnelEntity updatePoliceInfo3rdBind(PersonnelEntity personnelEntity, SyncPoliceDto policeDto) {
        personnelEntity.setPersonnelName(policeDto.getPersonnelName());
        personnelEntity.setNameAcronym(policeDto.getNameAcronym());
        personnelEntity.setIdNumber(policeDto.getIdNumber());
        if (personnelEntity.getPersonnelType() == null) {
            personnelEntity.setPersonnelType(Constants.PERSONNEL_TYPE.POLICE.id);
        }
        //1.机构调换
        if (policeDto.getOrgCode() != null) {
            OrgEntity orgEntity = orgRepository.getByOrgSn(policeDto.getOrgCode());
            if (orgEntity != null) {
                personnelEntity.setOrgId(orgEntity.getId());
            } else {
                personnelEntity.setOrgId(null);
                logger.error("cannot find orgCode: {}, orgName: {}", policeDto.getOrgCode(), policeDto.getOrgName());
            }
        } else {
            personnelEntity.setOrgId(null);
        }

        personnelEntity.setGender(policeDto.getGender());
        personnelEntity.setBirthday(policeDto.getBirthday());
        personnelEntity.setPhoneNumber(policeDto.getPhoneNumber());
        personnelEntity.setShortNumber(policeDto.getPdaNumber());
        personnelEntity.setTitle(policeDto.getTitle());
//        personnelEntity.setCreateTime(policeDto.getCreateTime());
        personnelEntity.setUpdateTime(policeDto.getUpdateTime());
        return personnelRepository.save(personnelEntity);
    }

    @Override
    public SyncExternalDto getExternalPersonInfo(String personnelSn) throws AppException {
        PersonnelEntity personnelEntity = personnelRepository.getByPersonnelSn(personnelSn);
        if (personnelEntity != null) {
            SyncExternalDto externalDto = new SyncExternalDto();
            externalDto.setCardNumber(personnelEntity.getCardNumber());
            externalDto.setPersonnelName(personnelEntity.getPersonnelName());
            externalDto.setNameAcronym(personnelEntity.getNameAcronym());
            externalDto.setPersonnelSn(personnelEntity.getPersonnelSn());
            externalDto.setIdNumber(personnelEntity.getIdNumber());
            externalDto.setGender(personnelEntity.getGender());
            externalDto.setPhoneNumber(personnelEntity.getPhoneNumber());
            externalDto.setTitle(personnelEntity.getTitle());
            externalDto.setUpdateTime(personnelEntity.getUpdateTime());
            externalDto.setDeleted(personnelEntity.getEnabled().equals(1) ? 0 : 1);
            return externalDto;
        } else {
            throw new AppException(Response.Status.NOT_FOUND.getStatusCode(),
                    CustomErrors.person_not_found.getCode(), CustomErrors.person_not_found.getReason(), "");
        }
    }

    @Override
    public Boolean updateExternalPersonInfo(String prisonId, SyncExternalDto externalDto) throws AppException {
        if (externalDto.getPersonnelSn() == null) {
            throw new AppException(Response.Status.FORBIDDEN.getStatusCode(),
                    CustomErrors.person_sn_is_null.getCode(), CustomErrors.person_sn_is_null.getReason(), "");
        }
        if (externalDto.getPersonnelName() == null) {
            throw new AppException(Response.Status.FORBIDDEN.getStatusCode(),
                    CustomErrors.person_name_is_null.getCode(), CustomErrors.person_name_is_null.getReason(), "");
        }
        if (externalDto.getNameAcronym() == null) {
            externalDto.setNameAcronym(Unidecode.initials(externalDto.getPersonnelName()));
        }
        if (externalDto.getCardNumber() != null) {
            if (!cardRepository.existsByCardNumber(externalDto.getCardNumber())) {
                //自动创建标签
                CardEntity cardEntity = new CardEntity();
                cardEntity.setCardNumber(externalDto.getCardNumber());
                cardEntity.setCardType(Constants.CARD_TYPE.CARD.id);
                cardEntity.setEnabled(Constants.ENABLE_STATUS.ENABLE.id);
                cardService.createCard(cardEntity);
            }
        }

        if (prisonSelfBindSet.contains(prisonId)) {
            //在自己平台绑定标签
            if (personnelRepository.existsByPersonnelSn(externalDto.getPersonnelSn())) {
                syncPrisonerService.updateExternalPersonInfoSelfBindUpdate(externalDto);
            } else {
                syncPrisonerService.updateExternalPersonInfoSelfBindCreate(externalDto);
            }
        } else if (prison3rdpartyBind.contains(prisonId)) {
            //在第三方平台绑定标签
            Long cardNumber = externalDto.getCardNumber();
            if (cardNumber != null) {
                PersonnelEntity personnelEntity = personnelRepository.getByCardNumber(cardNumber);
                if (personnelEntity != null && (!externalDto.getPersonnelSn().equals(personnelEntity.getPersonnelSn()))) {
                    throw new AppException(Response.Status.FORBIDDEN.getStatusCode(),
                            CustomErrors.card_number_conflict.getCode(), CustomErrors.card_number_conflict.getReason(),
                            "cardNumber:" + cardNumber + ", " + Long.toHexString(cardNumber));
                }
            }
            if (personnelRepository.existsByPersonnelSn(externalDto.getPersonnelSn())) {
                syncPrisonerService.updateExternalPersonInfo3rdBindUpdate(externalDto);
            } else {
                syncPrisonerService.updateExternalPersonInfo3rdBindCreate(externalDto);
            }
        } else {
            throw new AppException(Response.Status.FORBIDDEN.getStatusCode(),
                    CustomErrors.prisonId_not_found.getCode(), CustomErrors.prisonId_not_found.getReason(),
                    "prisonId:" + prisonId);
        }
        return true;
    }

    @Override
    public PersonnelEntity updateExternalPersonInfoSelfBindCreate(SyncExternalDto externalDto) {
        PersonnelEntity personnelEntity = new PersonnelEntity();
        personnelEntity.setPersonnelSn(externalDto.getPersonnelSn());
        personnelEntity.setPersonnelType(Constants.PERSONNEL_TYPE.VISITOR.id);
        personnelEntity.setCreateTime(new Timestamp(System.currentTimeMillis()));

        return updateExternalPersonInfoSelfBind(personnelEntity, externalDto);
    }

    @Override
    public PersonnelEntity updateExternalPersonInfoSelfBindUpdate(SyncExternalDto externalDto) {
        PersonnelEntity personnelEntity = personnelRepository.getByPersonnelSn(externalDto.getPersonnelSn());

        return updateExternalPersonInfoSelfBind(personnelEntity, externalDto);
    }

    private PersonnelEntity updateExternalPersonInfoSelfBind(PersonnelEntity personnelEntity, SyncExternalDto externalDto) {
        personnelEntity.setPersonnelName(externalDto.getPersonnelName());
        personnelEntity.setNameAcronym(externalDto.getNameAcronym());
        personnelEntity.setIdNumber(externalDto.getIdNumber());
        if (externalDto.getDeleted() != null && externalDto.getDeleted().equals(1)) {
            personnelEntity.setEnabled(Constants.ENABLE_STATUS.DISABLE.id);
        } else {
            personnelEntity.setEnabled(Constants.ENABLE_STATUS.ENABLE.id);
        }
        personnelEntity.setGender(externalDto.getGender());
        personnelEntity.setPhoneNumber(externalDto.getPhoneNumber());
        personnelEntity.setTitle(externalDto.getTitle());
        personnelEntity.setUpdateTime(externalDto.getUpdateTime());
        return personnelRepository.save(personnelEntity);
    }

    @Override
    public PersonnelEntity updateExternalPersonInfo3rdBindCreate(SyncExternalDto externalDto) {
        PersonnelEntity personnelEntity = new PersonnelEntity();
        personnelEntity.setPersonnelSn(externalDto.getPersonnelSn());
        personnelEntity.setPersonnelType(Constants.PERSONNEL_TYPE.VISITOR.id);
        personnelEntity.setCreateTime(new Timestamp(System.currentTimeMillis()));
        if (externalDto.getDeleted() != null && externalDto.getDeleted().equals(1)) {
            personnelEntity.setEnabled(Constants.ENABLE_STATUS.DISABLE.id);
            personnelEntity.setCardNumber(null);
        } else {
            personnelEntity.setEnabled(Constants.ENABLE_STATUS.ENABLE.id);
            personnelEntity.setCardNumber(externalDto.getCardNumber());
        }
        updateExternalPersonInfo3rdBind(personnelEntity, externalDto);
        //绑定手环
        if (personnelEntity.getCardNumber() != null) {
            msgDispatcher.bindPersonnelCard(personnelEntity.getId(), personnelEntity.getCardNumber());
        }
        return personnelEntity;
    }

    @Override
    public PersonnelEntity updateExternalPersonInfo3rdBindUpdate(SyncExternalDto externalDto) {
        PersonnelEntity personnelEntity = personnelRepository.getByPersonnelSn(externalDto.getPersonnelSn());
        if (externalDto.getDeleted() != null && externalDto.getDeleted().equals(1)) {
            //1.停用人员
            if (personnelEntity.getEnabled().equals(Constants.ENABLE_STATUS.ENABLE.id)) {
                //停用人员，解绑手环
                Long cardNumber = personnelEntity.getCardNumber();
                personnelEntity.setEnabled(Constants.ENABLE_STATUS.DISABLE.id);
                if (cardNumber != null) {
                    personnelEntity.setCardNumber(null);
                    msgDispatcher.unBindPersonnelCard(personnelEntity.getId(), cardNumber);
                }
            }
            //更新数据
            return updateExternalPersonInfo3rdBind(personnelEntity, externalDto);
        } else {
            //2.不停用人员
            if (personnelEntity.getEnabled().equals(Constants.ENABLE_STATUS.ENABLE.id)) {
                //调整手环编号
                Long cardNumber = personnelEntity.getCardNumber();
                Long newCardNumber = externalDto.getCardNumber();
                if (cardNumber != null) {
                    if (newCardNumber != null) {
                        if (!cardNumber.equals(newCardNumber)) {
                            //更换手环
                            personnelEntity.setCardNumber(newCardNumber);
                            msgDispatcher.unBindPersonnelCard(personnelEntity.getId(), cardNumber);
                            msgDispatcher.bindPersonnelCard(personnelEntity.getId(), newCardNumber);
                        }
                    } else {
                        //解绑手环
                        personnelEntity.setCardNumber(null);
                        msgDispatcher.unBindPersonnelCard(personnelEntity.getId(), cardNumber);
                    }
                } else {
                    if (newCardNumber != null) {
                        //绑定手环
                        personnelEntity.setCardNumber(newCardNumber);
                        msgDispatcher.bindPersonnelCard(personnelEntity.getId(), newCardNumber);
                    }
                }
            } else {
                //重新启用人员
                personnelEntity.setEnabled(Constants.ENABLE_STATUS.ENABLE.id);
                Long newCardNumber = externalDto.getCardNumber();
                if (newCardNumber != null) {
                    personnelEntity.setCardNumber(newCardNumber);
                    msgDispatcher.bindPersonnelCard(personnelEntity.getId(), newCardNumber);
                }
            }
            //更新数据
            return updateExternalPersonInfo3rdBind(personnelEntity, externalDto);
        }
    }

    private PersonnelEntity updateExternalPersonInfo3rdBind(PersonnelEntity personnelEntity, SyncExternalDto externalDto) {
        personnelEntity.setPersonnelName(externalDto.getPersonnelName());
        personnelEntity.setNameAcronym(externalDto.getNameAcronym());
        personnelEntity.setIdNumber(externalDto.getIdNumber());
        personnelEntity.setGender(externalDto.getGender());
        personnelEntity.setPhoneNumber(externalDto.getPhoneNumber());
        personnelEntity.setTitle(externalDto.getTitle());
        personnelEntity.setUpdateTime(externalDto.getUpdateTime());
        return personnelRepository.save(personnelEntity);
    }
}
